#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Datetime: 2021/10/05 13:14
# @Author  : CHEN Wang
# @Site    :
# @File    : glassnode.py
# @Software: PyCharm

"""
脚本说明: 从glassnode上获取相关指标信息
"""

import json
import time
import requests
import pandas as pd
import numpy as np
from quant_researcher.quant.project_tool.wrapper_tools.common_wrappers import deco_retry
from quant_researcher.quant.project_tool.time_tool import timestamp_to_datetime
from quant_researcher.quant.project_tool.logger.my_logger import LOG
from quant_researcher.quant.project_tool.time_tool import str_to_timestamp, date_shifter

# API_KEY = '1zV4A93k4g2KGDPRT2GJJ5XL5l9'    # jeffzhangzhenda@hotmail.com
API_KEY = '1zWq4Li0KlvJgokm8mJoXa8OeB2'  # dixinsuanlieth1@163.com

# 以下API地址从 https://docs.glassnode.com/api/addresses 获取，记得定期更新
api_http = {
    'Addresses': {'Depositing Addresses': 'https://api.glassnode.com/v1/metrics/addresses/sending_to_exchanges_count',
                  'Withdrawing Addresses': 'https://api.glassnode.com/v1/metrics/addresses/receiving_from_exchanges_count',
                  'Total Addresses': 'https://api.glassnode.com/v1/metrics/addresses/count',
                  'Sending Addresses': 'https://api.glassnode.com/v1/metrics/addresses/sending_count',
                  'Receiving Addresses': 'https://api.glassnode.com/v1/metrics/addresses/receiving_count',
                  'Active Addresses': 'https://api.glassnode.com/v1/metrics/addresses/active_count',
                  'New Addresses': 'https://api.glassnode.com/v1/metrics/addresses/new_non_zero_count',
                  'Accumulation Addresses': 'https://api.glassnode.com/v1/metrics/addresses/accumulation_count',
                  'Accumulation Balance': 'https://api.glassnode.com/v1/metrics/addresses/accumulation_balance',
                  'Addresses with Non-Zero Balance': 'https://api.glassnode.com/v1/metrics/addresses/non_zero_count',
                  'Addresses with Balance ≥ 0.01': 'https://api.glassnode.com/v1/metrics/addresses/min_point_zero_1_count',
                  'Addresses with Balance ≥ 0.1': 'https://api.glassnode.com/v1/metrics/addresses/min_point_1_count',
                  'Addresses with Balance ≥ 1': 'https://api.glassnode.com/v1/metrics/addresses/min_1_count',
                  'Addresses with Balance ≥ 10': 'https://api.glassnode.com/v1/metrics/addresses/min_10_count',
                  'Addresses with Balance ≥ 100': 'https://api.glassnode.com/v1/metrics/addresses/min_100_count',
                  'Addresses with Balance ≥ 1k': 'https://api.glassnode.com/v1/metrics/addresses/min_1k_count',
                  'Addresses with Balance ≥ 10k': 'https://api.glassnode.com/v1/metrics/addresses/min_10k_count',
                  'Addresses with Balance ≥ 32 ETH': 'https://api.glassnode.com/v1/metrics/addresses/min_32_count',
                  'Supply Held by Addresses with Balance less 0.001': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_less_0001',
                  'Supply Held by Addresses with Balance 0.001 - 0.01': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_0001_001',
                  'Supply Held by Addresses with Balance 0.01 - 0.1': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_001_01',
                  'Supply Held by Addresses with Balance 0.1 - 1': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_01_1',
                  'Supply Held by Addresses with Balance 1 - 10': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_1_10',
                  'Supply Held by Addresses with Balance 10 - 100': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_10_100',
                  'Supply Held by Addresses with Balance 100 - 1k': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_100_1k',
                  'Supply Held by Addresses with Balance 1k - 10k': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_1k_10k',
                  'Supply Held by Addresses with Balance 10k - 100k': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_10k_100k',
                  'Supply Held by Addresses with Balance more 100k': 'https://api.glassnode.com/v1/metrics/addresses/supply_balance_more_100k',
                  'Address Supply Distribution': 'https://api.glassnode.com/v1/metrics/addresses/supply_distribution_relative',
                  'Addresses with Balance ≥ $1': 'https://api.glassnode.com/v1/metrics/addresses/min_1_usd_count',
                  'Addresses with Balance ≥ $10': 'https://api.glassnode.com/v1/metrics/addresses/min_10_usd_count',
                  'Addresses with Balance ≥ $100': 'https://api.glassnode.com/v1/metrics/addresses/min_100_usd_count',
                  'Addresses with Balance ≥ $1k': 'https://api.glassnode.com/v1/metrics/addresses/min_1k_usd_count',
                  'Addresses with Balance ≥ $10k': 'https://api.glassnode.com/v1/metrics/addresses/min_10k_usd_count',
                  'Addresses with Balance ≥ $100k': 'https://api.glassnode.com/v1/metrics/addresses/min_100k_usd_count',
                  'Addresses with Balance ≥ $1M': 'https://api.glassnode.com/v1/metrics/addresses/min_1m_usd_count',
                  'Addresses in Profit': 'https://api.glassnode.com/v1/metrics/addresses/profit_count',
                  'Addresses in Loss': 'https://api.glassnode.com/v1/metrics/addresses/loss_count',
                  'Percent Addresses in Profit': 'https://api.glassnode.com/v1/metrics/addresses/profit_relative'},
    'Indicators': {'RHODL Ratio': 'https://api.glassnode.com/v1/metrics/indicators/rhodl_ratio',
                   'CVDD': 'https://api.glassnode.com/v1/metrics/indicators/cvdd',
                   'Balanced Price': 'https://api.glassnode.com/v1/metrics/indicators/balanced_price_usd',
                   'Hash Ribbon': 'https://api.glassnode.com/v1/metrics/indicators/hash_ribbon',
                   'Difficulty Ribbon': 'https://api.glassnode.com/v1/metrics/indicators/difficulty_ribbon',
                   'Difficulty Ribbon Compression': 'https://api.glassnode.com/v1/metrics/indicators/difficulty_ribbon_compression',
                   'NVT Ratio': 'https://api.glassnode.com/v1/metrics/indicators/nvt',
                   'NVT Signal': 'https://api.glassnode.com/v1/metrics/indicators/nvts',
                   'Velocity': 'https://api.glassnode.com/v1/metrics/indicators/velocity',
                   'Entity-Adjusted NVT': 'https://api.glassnode.com/v1/metrics/indicators/nvt_entity_adjusted',
                   'Supply-Adjusted CDD': 'https://api.glassnode.com/v1/metrics/indicators/cdd_supply_adjusted',
                   'Binary CDD': 'https://api.glassnode.com/v1/metrics/indicators/cdd_supply_adjusted_binary',
                   'Supply-Adjusted Dormancy': 'https://api.glassnode.com/v1/metrics/indicators/average_dormancy_supply_adjusted',
                   'SOPD (ATH-Partitioned)': 'https://api.glassnode.com/v1/metrics/indicators/spent_output_price_distribution_ath',
                   'SOPD (Percent-Partitioned)': 'https://api.glassnode.com/v1/metrics/indicators/spent_output_price_distribution_percent',
                   'Puell Multiple': 'https://api.glassnode.com/v1/metrics/indicators/puell_multiple',
                   'aSOPR': 'https://api.glassnode.com/v1/metrics/indicators/sopr_adjusted',
                   'Reserve Risk': 'https://api.glassnode.com/v1/metrics/indicators/reserve_risk',
                   'STH-SOPR': 'https://api.glassnode.com/v1/metrics/indicators/sopr_less_155',
                   'LTH-SOPR': 'https://api.glassnode.com/v1/metrics/indicators/sopr_more_155',
                   'Hodler Net Position Change': 'https://api.glassnode.com/v1/metrics/indicators/hodler_net_position_change',
                   'Hodled or Lost Coins': 'https://api.glassnode.com/v1/metrics/indicators/hodled_lost_coins',
                   'Coin Years Destroyed (CYD)': 'https://api.glassnode.com/v1/metrics/indicators/cyd',
                   'Supply-Adjusted CYD': 'https://api.glassnode.com/v1/metrics/indicators/cyd_supply_adjusted',
                   'Entity-Adjusted CYD': 'https://api.glassnode.com/v1/metrics/indicators/cyd_account_based',
                   'Entity- and Supply-Adjusted CYD': 'https://api.glassnode.com/v1/metrics/indicators/cyd_account_based_supply_adjusted',
                   '90D Coin Days Destroyed (CDD-90)': 'https://api.glassnode.com/v1/metrics/indicators/cdd90_age_adjusted',
                   'Entity-Adjusted 90D Coin Days Destroyed (eCDD-90)': 'https://api.glassnode.com/v1/metrics/indicators/cdd90_account_based_age_adjusted',
                   'SOPR': 'https://api.glassnode.com/v1/metrics/indicators/sopr',
                   'Coin Days Destroyed (CDD)': 'https://api.glassnode.com/v1/metrics/indicators/cdd',
                   'ASOL': 'https://api.glassnode.com/v1/metrics/indicators/asol',
                   'MSOL': 'https://api.glassnode.com/v1/metrics/indicators/msol',
                   'Dormancy': 'https://api.glassnode.com/v1/metrics/indicators/average_dormancy',
                   'Liveliness': 'https://api.glassnode.com/v1/metrics/indicators/liveliness',
                   'Relative Unrealized Profit': 'https://api.glassnode.com/v1/metrics/indicators/unrealized_profit',
                   'Relative Unrealized Loss': 'https://api.glassnode.com/v1/metrics/indicators/unrealized_loss',
                   'Net Unrealized Profit Loss (NUPL)': 'https://api.glassnode.com/v1/metrics/indicators/net_unrealized_profit_loss',
                   'STH-NUPL': 'https://api.glassnode.com/v1/metrics/indicators/nupl_less_155',
                   'LTH-NUPL': 'https://api.glassnode.com/v1/metrics/indicators/nupl_more_155',
                   'Entity-Adjusted SOPR': 'https://api.glassnode.com/v1/metrics/indicators/sopr_account_based',
                   'Entity-Adjusted CDD': 'https://api.glassnode.com/v1/metrics/indicators/cdd_account_based',
                   'Entity-Adjusted ASOL': 'https://api.glassnode.com/v1/metrics/indicators/asol_account_based',
                   'Entity-Adjusted MSOL': 'https://api.glassnode.com/v1/metrics/indicators/msol_account_based',
                   'Entity-Adjusted Dormancy': 'https://api.glassnode.com/v1/metrics/indicators/dormancy_account_based',
                   'Entity-Adjusted Dormancy Flow': 'https://api.glassnode.com/v1/metrics/indicators/dormancy_flow',
                   'Entity-Adjusted Liveliness': 'https://api.glassnode.com/v1/metrics/indicators/liveliness_account_based',
                   'Entity-Adjusted MVRV': 'https://api.glassnode.com/v1/metrics/indicators/mvrv_account_based',
                   'Entity-Adjusted Realized Cap': 'https://api.glassnode.com/v1/metrics/indicators/rcap_account_based',
                   'Entity-Adjusted Unrealized Profit': 'https://api.glassnode.com/v1/metrics/indicators/unrealized_profit_account_based',
                   'Entity-Adjusted Unrealized Loss': 'https://api.glassnode.com/v1/metrics/indicators/unrealized_loss_account_based',
                   'Entity-Adjusted NUPL': 'https://api.glassnode.com/v1/metrics/indicators/net_unrealized_profit_loss_account_based',
                   'Entity-Adjusted STH-NUPL': 'https://api.glassnode.com/v1/metrics/indicators/nupl_less_155_account_based',
                   'Entity-Adjusted LTH-NUPL': 'https://api.glassnode.com/v1/metrics/indicators/nupl_more_155_account_based',
                   'Net Realized Profit Loss': 'https://api.glassnode.com/v1/metrics/indicators/net_realized_profit_loss',
                   'Realized P L Ratio': 'https://api.glassnode.com/v1/metrics/indicators/realized_profit_loss_ratio',
                   'Stock-to-Flow Ratio': 'https://api.glassnode.com/v1/metrics/indicators/stock_to_flow_ratio',
                   'Stock-to-Flow Deflection': 'https://api.glassnode.com/v1/metrics/indicators/stock_to_flow_deflection',
                   'Realized Profit': 'https://api.glassnode.com/v1/metrics/indicators/realized_profit',
                   'Realized Loss': 'https://api.glassnode.com/v1/metrics/indicators/realized_loss',
                   # SSR指标自己计算
                   'Stablecoin Supply Ratio (SSR)': 'https://api.glassnode.com/v1/metrics/indicators/ssr',
                   'Stablecoin Supply Ratio (SSR) Oscillator': 'https://api.glassnode.com/v1/metrics/indicators/ssr_oscillator',
                   'URPD (ATH-Partitioned)': 'https://api.glassnode.com/v1/metrics/indicators/utxo_realized_price_distribution_ath',
                   'URPD (Percent-Partitioned)': 'https://api.glassnode.com/v1/metrics/indicators/utxo_realized_price_distribution_percent',
                   'Spent Output Age Bands': 'https://api.glassnode.com/v1/metrics/indicators/soab',
                   'Spent Outputs less 1h': 'https://api.glassnode.com/v1/metrics/indicators/sol_1h',
                   'Spent Outputs 1h-24h': 'https://api.glassnode.com/v1/metrics/indicators/sol_1h_24h',
                   'Spent Outputs 1d-1w': 'https://api.glassnode.com/v1/metrics/indicators/sol_1d_1w',
                   'Spent Outputs 1w-1m': 'https://api.glassnode.com/v1/metrics/indicators/sol_1w_1m',
                   'Spent Outputs 1m-3m': 'https://api.glassnode.com/v1/metrics/indicators/sol_1m_3m',
                   'Spent Outputs 3m-6m': 'https://api.glassnode.com/v1/metrics/indicators/sol_3m_6m',
                   'Spent Outputs 6m-12m': 'https://api.glassnode.com/v1/metrics/indicators/sol_6m_12m',
                   'Spent Outputs 1y-2y': 'https://api.glassnode.com/v1/metrics/indicators/sol_1y_2y',
                   'Spent Outputs 2y-3y': 'https://api.glassnode.com/v1/metrics/indicators/sol_2y_3y',
                   'Spent Outputs 3y-5y': 'https://api.glassnode.com/v1/metrics/indicators/sol_3y_5y',
                   'Spent Outputs 5y-7y': 'https://api.glassnode.com/v1/metrics/indicators/sol_5y_7y',
                   'Spent Outputs 7y-10y': 'https://api.glassnode.com/v1/metrics/indicators/sol_7y_10y',
                   'Spent Outputs more 10y': 'https://api.glassnode.com/v1/metrics/indicators/sol_more_10y',
                   'Spent Volume Age Bands (SVAB)': 'https://api.glassnode.com/v1/metrics/indicators/svab',
                   'Spent Volume less 1h': 'https://api.glassnode.com/v1/metrics/indicators/svl_1h',
                   'Spent Volume 1h-24h': 'https://api.glassnode.com/v1/metrics/indicators/svl_1h_24h',
                   'Spent Volume 1d-1w': 'https://api.glassnode.com/v1/metrics/indicators/svl_1d_1w',
                   'Spent Volume 1w-1m': 'https://api.glassnode.com/v1/metrics/indicators/svl_1w_1m',
                   'Spent Volume 1m-3m': 'https://api.glassnode.com/v1/metrics/indicators/svl_1m_3m',
                   'Spent Volume 3m-6m': 'https://api.glassnode.com/v1/metrics/indicators/svl_3m_6m',
                   'Spent Volume 6m-12m': 'https://api.glassnode.com/v1/metrics/indicators/svl_6m_12m',
                   'Spent Volume 1y-2y': 'https://api.glassnode.com/v1/metrics/indicators/svl_1y_2y',
                   'Spent Volume 2y-3y': 'https://api.glassnode.com/v1/metrics/indicators/svl_2y_3y',
                   'Spent Volume 3y-5y': 'https://api.glassnode.com/v1/metrics/indicators/svl_3y_5y',
                   'Spent Volume 5y-7y': 'https://api.glassnode.com/v1/metrics/indicators/svl_5y_7y',
                   'Spent Volume 7y-10y': 'https://api.glassnode.com/v1/metrics/indicators/svl_7y_10y',
                   'Spent Volume more 10y': 'https://api.glassnode.com/v1/metrics/indicators/svl_more_10y',
                   'Bitcoin Volatility Index (BVIN)': 'https://api.glassnode.com/v1/metrics/indicators/bvin',
                   'Investor Capitalization': 'https://api.glassnode.com/v1/metrics/indicators/investor_capitalization',
                   'Realized Profits-to-Value (RPV) Ratio': 'https://api.glassnode.com/v1/metrics/indicators/realized_profits_to_value_ratio',
                   'Pi Cycle Top Indicator': 'https://api.glassnode.com/v1/metrics/indicators/pi_cycle_top'},
    'Market': {'Price Drawdown from ATH': 'https://api.glassnode.com/v1/metrics/market/price_drawdown_relative',
               'Delta Cap': 'https://api.glassnode.com/v1/metrics/market/deltacap_usd',
               'Market Cap': 'https://api.glassnode.com/v1/metrics/market/marketcap_usd',
               'MVRV Ratio': 'https://api.glassnode.com/v1/metrics/market/mvrv',
               'Realized Cap': 'https://api.glassnode.com/v1/metrics/market/marketcap_realized_usd',
               'MVRV Z-Score': 'https://api.glassnode.com/v1/metrics/market/mvrv_z_score',
               'STH-MVRV': 'https://api.glassnode.com/v1/metrics/market/mvrv_less_155',
               'LTH-MVRV': 'https://api.glassnode.com/v1/metrics/market/mvrv_more_155',
               'Realized Price': 'https://api.glassnode.com/v1/metrics/market/price_realized_usd'},
    'Mining': {'Difficulty': 'https://api.glassnode.com/v1/metrics/mining/difficulty_latest',
               'Hash Rate': 'https://api.glassnode.com/v1/metrics/mining/hash_rate_mean',
               'Miner Revenue (Total)': 'https://api.glassnode.com/v1/metrics/mining/revenue_sum',
               'Miner Revenue (Fees)': 'https://api.glassnode.com/v1/metrics/mining/revenue_from_fees',
               'Miner Revenue (Block Rewards)': 'https://api.glassnode.com/v1/metrics/mining/volume_mined_sum',
               'Miner Outflow Multiple': 'https://api.glassnode.com/v1/metrics/mining/miners_outflow_multiple',
               'Thermocap': 'https://api.glassnode.com/v1/metrics/mining/thermocap',
               'Market Cap to Thermocap Ratio': 'https://api.glassnode.com/v1/metrics/mining/marketcap_thermocap_ratio',
               'Miner Unspent Supply': 'https://api.glassnode.com/v1/metrics/mining/miners_unspent_supply'},
    'Derivatives': {
        # funding_rate 自己计算
        'Futures Perpetual Funding Rate': 'https://api.glassnode.com/v1/metrics/derivatives/futures_funding_rate_perpetual',
        'Futures Perpetual Funding Rate (All)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_funding_rate_perpetual_all',
        'Cash-Margined Futures Open Interest': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_cash_margin_sum',
        'Crypto-Margined Futures Open Interest': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_crypto_margin_sum',
        'Percent Crypto-Margined Futures Open Interest': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_crypto_margin_relative',
        'Futures Estimated Leverage Ratio': 'https://api.glassnode.com/v1/metrics/derivatives/futures_estimated_leverage_ratio',
        'Options ATM Implied Volatility (1 Week)': 'https://api.glassnode.com/v1/metrics/derivatives/options_atm_implied_volatility_1_week',
        'Options ATM Implied Volatility (1 Month)': 'https://api.glassnode.com/v1/metrics/derivatives/options_atm_implied_volatility_1_month',
        'Options ATM Implied Volatility (3 Months)': 'https://api.glassnode.com/v1/metrics/derivatives/options_atm_implied_volatility_3_months',
        'Options ATM Implied Volatility (6 Months)': 'https://api.glassnode.com/v1/metrics/derivatives/options_atm_implied_volatility_6_months',
        'Options ATM Implied Volatility (All)': 'https://api.glassnode.com/v1/metrics/derivatives/options_atm_implied_volatility_all',
        'Futures Volume': 'https://api.glassnode.com/v1/metrics/derivatives/futures_volume_daily_sum',
        'Futures Volume Perpetual': 'https://api.glassnode.com/v1/metrics/derivatives/futures_volume_daily_perpetual_sum',
        'Futures Open Interest': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_sum',
        'Futures Open Interest Perpetual': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_perpetual_sum',
        'Futures Short Liquidations (Total)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_liquidated_volume_short_sum',
        'Futures Short Liquidations (Mean)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_liquidated_volume_short_mean',
        'Futures Long Liquidations (Total)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_liquidated_volume_long_sum',
        'Futures Long Liquidations (Mean)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_liquidated_volume_long_mean',
        'Futures Long Liquidations Dominance': 'https://api.glassnode.com/v1/metrics/derivatives/futures_liquidated_volume_long_relative',
        'Futures Volume (Stacked)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_volume_daily_sum_all',
        'Futures Volume Perpetual (Stacked)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_volume_daily_perpetual_sum_all',
        'Futures Open Interest (Stacked)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_sum_all',
        'Futures Open Interest Perpetual (Stacked)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_perpetual_sum_all',
        'Options Volume': 'https://api.glassnode.com/v1/metrics/derivatives/options_volume_daily_sum',
        'Options Open Interest': 'https://api.glassnode.com/v1/metrics/derivatives/options_open_interest_sum',
        'Options OI by Strike Price': 'https://api.glassnode.com/v1/metrics/derivatives/options_open_interest_distribution',
        'Futures Term Structure': 'https://api.glassnode.com/v1/metrics/derivatives/futures_term_structure',
        'Futures Term Structure by Exchange': 'https://api.glassnode.com/v1/metrics/derivatives/futures_term_structure_by_exchange',
        'Futures Annualized Rolling Basis (3M)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_annualized_basis_3m',
        'Futures Open Interest (Current)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_open_interest_latest',
        'Futures Volume (Latest 24h)': 'https://api.glassnode.com/v1/metrics/derivatives/futures_volume_daily_latest'},
    'Distribution': {'Exchange Balance (Total)': 'https://api.glassnode.com/v1/metrics/distribution/balance_exchanges',
                     'Exchange Net Position Change': 'https://api.glassnode.com/v1/metrics/distribution/exchange_net_position_change',
                     'Exchange Balance (Percent)': 'https://api.glassnode.com/v1/metrics/distribution/balance_exchanges_relative',
                     'Exchange Balance (Stacked)': 'https://api.glassnode.com/v1/metrics/distribution/balance_exchanges_all',
                     'Miner Balance (Stacked)': 'https://api.glassnode.com/v1/metrics/distribution/balance_miners_all',
                     'Miner Net Position Change': 'https://api.glassnode.com/v1/metrics/distribution/balance_miners_change',
                     'OTC Desks Holdings': 'https://api.glassnode.com/v1/metrics/distribution/balance_otc_desks',
                     'Supply of Top 1% Addresses': 'https://api.glassnode.com/v1/metrics/distribution/balance_1pct_holders',
                     'Gini Coefficient': 'https://api.glassnode.com/v1/metrics/distribution/gini',
                     'Herfindahl Index': 'https://api.glassnode.com/v1/metrics/distribution/herfindahl',
                     'Supply in Smart Contracts': 'https://api.glassnode.com/v1/metrics/distribution/supply_contracts',
                     'Miner Balance': 'https://api.glassnode.com/v1/metrics/distribution/balance_miners_sum'},
    'Entities': {'Sending Entities': 'https://api.glassnode.com/v1/metrics/entities/sending_count',
                 'Receiving Entities': 'https://api.glassnode.com/v1/metrics/entities/receiving_count',
                 'Active Entities': 'https://api.glassnode.com/v1/metrics/entities/active_count',
                 'New Entities': 'https://api.glassnode.com/v1/metrics/entities/new_count',
                 'Entities Net Growth': 'https://api.glassnode.com/v1/metrics/entities/net_growth_count',
                 'Number of Whales': 'https://api.glassnode.com/v1/metrics/entities/min_1k_count',
                 'Supply Held by Entities with Balance less 0.001': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_less_0001',
                 'Supply Held by Entities with Balance 0.001 - 0.01': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_0001_001',
                 'Supply Held by Entities with Balance 0.01 - 0.1': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_001_01',
                 'Supply Held by Entities with Balance 0.1 - 1': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_01_1',
                 'Supply Held by Entities with Balance 1 - 10': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_1_10',
                 'Supply Held by Entities with Balance 10 - 100': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_10_100',
                 'Supply Held by Entities with Balance 100 - 1k': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_100_1k',
                 'Supply Held by Entities with Balance 1k - 10k': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_1k_10k',
                 'Supply Held by Entities with Balance 10k - 100k': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_10k_100k',
                 'Supply Held by Entities with Balance more 100k': 'https://api.glassnode.com/v1/metrics/entities/supply_balance_more_100k',
                 'Entities Supply Distribution': 'https://api.glassnode.com/v1/metrics/entities/supply_distribution_relative',
                 'Percent Entities in Profit': 'https://api.glassnode.com/v1/metrics/entities/profit_relative'},
    'Supply': {'Liquid and Illiquid Supply': 'https://api.glassnode.com/v1/metrics/supply/liquid_illiquid_sum',
               'Liquid Supply': 'https://api.glassnode.com/v1/metrics/supply/liquid_sum',
               'Highly Liquid Supply': 'https://api.glassnode.com/v1/metrics/supply/highly_liquid_sum',
               'Illiquid Supply': 'https://api.glassnode.com/v1/metrics/supply/illiquid_sum',
               'Liquid Supply Change': 'https://api.glassnode.com/v1/metrics/supply/liquid_change',
               'Illiquid Supply Change': 'https://api.glassnode.com/v1/metrics/supply/illiquid_change',
               'Circulating Supply': 'https://api.glassnode.com/v1/metrics/supply/current',
               'Minted Supply': 'https://api.glassnode.com/v1/metrics/supply/minted',
               'Burned Supply': 'https://api.glassnode.com/v1/metrics/supply/burned',
               'Issuance': 'https://api.glassnode.com/v1/metrics/supply/issued',
               'Inflation Rate': 'https://api.glassnode.com/v1/metrics/supply/inflation_rate',
               'Revived Supply 1+ Years': 'https://api.glassnode.com/v1/metrics/supply/revived_more_1y_sum',
               'Revived Supply 2+ Years': 'https://api.glassnode.com/v1/metrics/supply/revived_more_2y_sum',
               'Revived Supply 3+ Years': 'https://api.glassnode.com/v1/metrics/supply/revived_more_3y_sum',
               'Revived Supply 5+ Years': 'https://api.glassnode.com/v1/metrics/supply/revived_more_5y_sum',
               'Supply Last Active less 24h': 'https://api.glassnode.com/v1/metrics/supply/active_24h',
               'Supply Last Active 1d-1w': 'https://api.glassnode.com/v1/metrics/supply/active_1d_1w',
               'Supply Last Active 1w-1m': 'https://api.glassnode.com/v1/metrics/supply/active_1w_1m',
               'Supply Last Active 1m-3m': 'https://api.glassnode.com/v1/metrics/supply/active_1m_3m',
               'Supply Last Active 3m-6m': 'https://api.glassnode.com/v1/metrics/supply/active_3m_6m',
               'Supply Last Active 6m-12m': 'https://api.glassnode.com/v1/metrics/supply/active_6m_12m',
               'Supply Last Active 1y-2y': 'https://api.glassnode.com/v1/metrics/supply/active_1y_2y',
               'Supply Last Active 2y-3y': 'https://api.glassnode.com/v1/metrics/supply/active_2y_3y',
               'Supply Last Active 3y-5y': 'https://api.glassnode.com/v1/metrics/supply/active_3y_5y',
               'Supply Last Active 5y-7y': 'https://api.glassnode.com/v1/metrics/supply/active_5y_7y',
               'Supply Last Active 7y-10y': 'https://api.glassnode.com/v1/metrics/supply/active_7y_10y',
               'Supply Last Active more 10y': 'https://api.glassnode.com/v1/metrics/supply/active_more_10y',
               'HODL Waves': 'https://api.glassnode.com/v1/metrics/supply/hodl_waves',
               'Supply Last Active 1+ Years Ago': 'https://api.glassnode.com/v1/metrics/supply/active_more_1y_percent',
               'Supply Last Active 2+ Years Ago': 'https://api.glassnode.com/v1/metrics/supply/active_more_2y_percent',
               'Supply Last Active 3+ Years Ago': 'https://api.glassnode.com/v1/metrics/supply/active_more_3y_percent',
               'Supply Last Active 5+ Years Ago': 'https://api.glassnode.com/v1/metrics/supply/active_more_5y_percent',
               'Realized Cap HODL Waves': 'https://api.glassnode.com/v1/metrics/supply/rcap_hodl_waves',
               'Short to Long-Term Realized Value (SLRV) Ratio': 'https://api.glassnode.com/v1/metrics/supply/sth_lth_realized_value_ratio',
               'Adjusted Supply': 'https://api.glassnode.com/v1/metrics/supply/current_adjusted',
               'Supply in Profit': 'https://api.glassnode.com/v1/metrics/supply/profit_sum',
               'Supply in Loss': 'https://api.glassnode.com/v1/metrics/supply/loss_sum',
               'Percent Supply in Profit': 'https://api.glassnode.com/v1/metrics/supply/profit_relative',
               'Short-Term Holder Supply': 'https://api.glassnode.com/v1/metrics/supply/sth_sum',
               'Long-Term Holder Supply': 'https://api.glassnode.com/v1/metrics/supply/lth_sum',
               'Short-Term Holder Supply in Loss': 'https://api.glassnode.com/v1/metrics/supply/sth_loss_sum',
               'Long-Term Holder Supply in Loss': 'https://api.glassnode.com/v1/metrics/supply/lth_loss_sum',
               'Short-Term Holder Supply in Profit': 'https://api.glassnode.com/v1/metrics/supply/sth_profit_sum',
               'Long-Term Holder Supply in Profit': 'https://api.glassnode.com/v1/metrics/supply/lth_profit_sum',
               'Relative Long Short-Term Holder Supply': 'https://api.glassnode.com/v1/metrics/supply/lth_sth_profit_loss_relative',
               'Long-Term Holder Position Change': 'https://api.glassnode.com/v1/metrics/supply/lth_net_change',
               'Short-Term Holder Profit/Loss Ratio': 'https://api.glassnode.com/v1/metrics/supply/sth_profit_loss_ratio'},
    'Transactions': {'Transaction Count': 'https://api.glassnode.com/v1/metrics/transactions/count',
                     'Transaction Rate': 'https://api.glassnode.com/v1/metrics/transactions/rate',
                     'Contract Calls (External)': 'https://api.glassnode.com/v1/metrics/transactions/contract_calls_external_count',
                     'Contract Calls (Internal)': 'https://api.glassnode.com/v1/metrics/transactions/contract_calls_internal_count',
                     'Transaction Size (Mean)': 'https://api.glassnode.com/v1/metrics/transactions/size_mean',
                     'Transaction Size (Total)': 'https://api.glassnode.com/v1/metrics/transactions/size_sum',
                     'Total Transfer Volume by Size (Entity-Adjusted)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_by_size_entity_adjusted_sum',
                     'Relative Transfer Volume by Size (Entity-Adjusted)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_by_size_entity_adjusted_relative',
                     'OTC Desks Incoming Transactions': 'https://api.glassnode.com/v1/metrics/transactions/transfers_to_otc_desks_count',
                     'OTC Desks Outgoing Transactions': 'https://api.glassnode.com/v1/metrics/transactions/transfers_from_otc_desks_count',
                     'OTC Desks Inflows': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_to_otc_desks_sum',
                     'OTC Desks Outflows': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_from_otc_desks_sum',
                     'Transfer Count': 'https://api.glassnode.com/v1/metrics/transactions/transfers_count',
                     'Transfer Rate': 'https://api.glassnode.com/v1/metrics/transactions/transfers_rate',
                     'Transfer Volume (Total)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_sum',
                     'Transfer Volume (Mean)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_mean',
                     'Transfer Volume (Median)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_median',
                     'Change-Adjusted Volume (Total)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_adjusted_sum',
                     'Change-Adjusted Volume (Mean)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_adjusted_mean',
                     'Change-Adjusted Volume (Median)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_adjusted_median',
                     'Percent Volume in Profit': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_profit_relative',
                     'Transfer Volume in Profit': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_profit_sum',
                     'Transfer Volume in Loss': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_loss_sum',
                     'Entity-Adjusted Transaction Count': 'https://api.glassnode.com/v1/metrics/transactions/entity_adjusted_count',
                     'Entity-Adjusted Volume (Total)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_entity_adjusted_sum',
                     'Entity-Adjusted Volume (Mean)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_entity_adjusted_mean',
                     'Entity-Adjusted Volume (Median)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_entity_adjusted_median',
                     'Miner Outgoing Transfers': 'https://api.glassnode.com/v1/metrics/transactions/transfers_from_miners_count',
                     'Miner Incoming Transfers': 'https://api.glassnode.com/v1/metrics/transactions/transfers_to_miners_count',
                     'Miner Outflow Volume': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_from_miners_sum',
                     'Miner Inflow Volume': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_to_miners_sum',
                     'Miner Netflow Volume': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_miners_net',
                     'Inter-Exchange Transfers': 'https://api.glassnode.com/v1/metrics/transactions/transfers_between_exchanges_count',
                     'Inter-Exchange Volume': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_between_exchanges_sum',
                     'Miners to Exchanges': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_miners_to_exchanges',
                     'Miners to Exchanges (Stacked)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_miners_to_exchanges_all',
                     'Exchange Inflow Volume (Mean)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_to_exchanges_mean',
                     'Exchange Outflow Volume (Mean)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_from_exchanges_mean',
                     'Exchange Net Flow Volume': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_exchanges_net',
                     'Exchange Deposits': 'https://api.glassnode.com/v1/metrics/transactions/transfers_to_exchanges_count',
                     'Exchange Withdrawals': 'https://api.glassnode.com/v1/metrics/transactions/transfers_from_exchanges_count',
                     'Exchange Inflow Volume (Total)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_to_exchanges_sum',
                     'Exchange Outflow Volume (Total)': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_from_exchanges_sum',
                     'In-house Exchange Volume': 'https://api.glassnode.com/v1/metrics/transactions/transfers_volume_within_exchanges_sum',
                     },
    'Mempool': {
        'Mempool Transaction Count by Cohort': 'https://api.glassnode.com/v1/metrics/mempool/txs_count_distribution',
        'Mempool Transaction Count': 'https://api.glassnode.com/v1/metrics/mempool/txs_count_sum',
        'Mempool Transactions Size by Cohort (vByte)': 'https://api.glassnode.com/v1/metrics/mempool/txs_size_distribution',
        'Mempool Transactions Size (vByte)': 'https://api.glassnode.com/v1/metrics/mempool/txs_size_sum',
        'Mempool Total Amount of Fees by Cohort (vByte)': 'https://api.glassnode.com/v1/metrics/mempool/fees_distribution',
        'Mempool Total Amount of Fees': 'https://api.glassnode.com/v1/metrics/mempool/fees_sum',
        'Mempool Total Amount of Coins by Cohort (vByte)': 'https://api.glassnode.com/v1/metrics/mempool/txs_value_distribution',
        'Mempool Total Amount of Coins': 'https://api.glassnode.com/v1/metrics/mempool/txs_value_sum',
        'Mempool Average Relative Fee': 'https://api.glassnode.com/v1/metrics/mempool/fees_average_relative',
        'Mempool Median Relative Fee': 'https://api.glassnode.com/v1/metrics/mempool/fees_median_relative'},
    'ETH 2.0': {'New Deposits': 'https://api.glassnode.com/v1/metrics/eth2/staking_deposits_count',
                'New Value Staked': 'https://api.glassnode.com/v1/metrics/eth2/staking_volume_sum',
                'New Validators': 'https://api.glassnode.com/v1/metrics/eth2/staking_validators_count',
                'Total Number of Deposits': 'https://api.glassnode.com/v1/metrics/eth2/staking_total_deposits_count',
                'Total Value Staked': 'https://api.glassnode.com/v1/metrics/eth2/staking_total_volume_sum',
                'Total Number of Validators': 'https://api.glassnode.com/v1/metrics/eth2/staking_total_validators_count',
                'Phase 0 Staking Goal': 'https://api.glassnode.com/v1/metrics/eth2/staking_phase_0_goal_percent'},
    'DeFi': {'Total Value Locked in DeFi (TVL)': 'https://api.glassnode.com/v1/metrics/defi/total_value_locked'},
    'Fees': {'Gas Used (Total)': 'https://api.glassnode.com/v1/metrics/fees/gas_used_sum',
             'Gas Used (Mean)': 'https://api.glassnode.com/v1/metrics/fees/gas_used_mean',
             'Gas Used (Median)': 'https://api.glassnode.com/v1/metrics/fees/gas_used_median',
             'Transaction Gas Limit (Mean)': 'https://api.glassnode.com/v1/metrics/fees/gas_limit_tx_mean',
             'Transaction Gas Limit (Median)': 'https://api.glassnode.com/v1/metrics/fees/gas_limit_tx_median',
             'Gas Price (Mean)': 'https://api.glassnode.com/v1/metrics/fees/gas_price_mean',
             'Gas Price (Median)': 'https://api.glassnode.com/v1/metrics/fees/gas_price_median',
             'Fees (Total)': 'https://api.glassnode.com/v1/metrics/fees/volume_sum',
             'Fees (Mean)': 'https://api.glassnode.com/v1/metrics/fees/volume_mean',
             'Fees (Median)': 'https://api.glassnode.com/v1/metrics/fees/volume_median',
             'Fee Ratio Multiple (FRM)': 'https://api.glassnode.com/v1/metrics/fees/fee_ratio_multiple',
             'Exchange Fee Dominance': 'https://api.glassnode.com/v1/metrics/fees/exchanges_relative',
             'Exchange Fees (Total)': 'https://api.glassnode.com/v1/metrics/fees/exchanges_sum',
             'Exchange Fees (Mean)': 'https://api.glassnode.com/v1/metrics/fees/exchanges_mean'},
    'Institutions': {'Grayscale Holdings': 'https://api.glassnode.com/v1/metrics/institutions/grayscale_holdings_sum',
                     'Grayscale Flows': 'https://api.glassnode.com/v1/metrics/institutions/grayscale_flows_sum',
                     'Grayscale Premium': 'https://api.glassnode.com/v1/metrics/institutions/grayscale_premium_percent',
                     'Grayscale AUM': 'https://api.glassnode.com/v1/metrics/institutions/grayscale_aum_sum',
                     'Grayscale Market Price': 'https://api.glassnode.com/v1/metrics/institutions/grayscale_market_price_usd',
                     'Purpose Bitcoin ETF Holdings': 'https://api.glassnode.com/v1/metrics/institutions/purpose_etf_holdings_sum',
                     'Purpose Bitcoin ETF Flows': 'https://api.glassnode.com/v1/metrics/institutions/purpose_etf_flows_sum',
                     'The Bitcoin Fund (QBTC) Holdings': 'https://api.glassnode.com/v1/metrics/institutions/qbtc_holdings_sum',
                     'The Bitcoin Fund (QBTC) Flows': 'https://api.glassnode.com/v1/metrics/institutions/qbtc_flows_sum',
                     'The Bitcoin Fund (QBTC) Premium': 'https://api.glassnode.com/v1/metrics/institutions/qbtc_premium_percent',
                     'The Bitcoin Fund (QBTC) AUM': 'https://api.glassnode.com/v1/metrics/institutions/qbtc_aum_sum',
                     'The Bitcoin Fund (QBTC) Market Price': 'https://api.glassnode.com/v1/metrics/institutions/qbtc_market_price_usd',
                     'The Bitcoin Fund (QBTC.U) Holdings': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qbtc_holdings_sum',
                     'The Bitcoin Fund (QBTC.U) Flows': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qbtc_flows_sum',
                     'The Bitcoin Fund (QBTC.U) Premium': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qbtc_premium_percent',
                     'The Bitcoin Fund (QBTC.U) Outstanding Units': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qbtc_outstanding_units_sum',
                     'The Bitcoin Fund (QBTC.U) AUM': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qbtc_aum_sum',
                     'The Bitcoin Fund (QBTC.U) Market Price': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qbtc_market_price_usd',
                     '3iQ CoinShares Bitcoin ETF (BTCQ.U) Holdings': 'https://api.glassnode.com/v1/metrics/institutions/3iq_btcq_holdings_sum',
                     '3iQ CoinShares Bitcoin ETF (BTCQ.U) Flows': 'https://api.glassnode.com/v1/metrics/institutions/3iq_btcq_flows_sum',
                     '3iQ CoinShares Bitcoin ETF (BTCQ.U) Premium': 'https://api.glassnode.com/v1/metrics/institutions/3iq_btcq_premium_percent',
                     '3iQ CoinShares Bitcoin ETF (BTCQ.U) Outstanding Units': 'https://api.glassnode.com/v1/metrics/institutions/3iq_btcq_outstanding_units_sum',
                     '3iQ CoinShares Bitcoin ETF (BTCQ.U) AUM': 'https://api.glassnode.com/v1/metrics/institutions/3iq_btcq_aum_sum',
                     '3iQ CoinShares Bitcoin ETF (BTCQ.U) Market Price': 'https://api.glassnode.com/v1/metrics/institutions/3iq_btcq_market_price_usd',
                     'The Ether Fund (QETH.U) Holdings': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qeth_holdings_sum',
                     'The Ether Fund (QETH.U) Flows': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qeth_flows_sum',
                     'The Ether Fund (QETH.U) Premium': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qeth_premium_percent',
                     'The Ether Fund (QETH.U) Outstanding Units': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qeth_outstanding_units_sum',
                     'The Ether Fund (QETH.U) AUM': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qeth_aum_sum',
                     'The Ether Fund (QETH.U) Market Price': 'https://api.glassnode.com/v1/metrics/institutions/3iq_qeth_market_price_usd',
                     '3iQ CoinShares Ether ETF (ETHQ.U) Holdings': 'https://api.glassnode.com/v1/metrics/institutions/3iq_ethq_holdings_sum',
                     '3iQ CoinShares Ether ETF (ETHQ.U) Flows': 'https://api.glassnode.com/v1/metrics/institutions/3iq_ethq_flows_sum',
                     '3iQ CoinShares Ether ETF (ETHQ.U) Premium': 'https://api.glassnode.com/v1/metrics/institutions/3iq_ethq_premium_percent',
                     '3iQ CoinShares Ether ETF (ETHQ.U) Outstanding Units': 'https://api.glassnode.com/v1/metrics/institutions/3iq_ethq_outstanding_units_sum',
                     '3iQ CoinShares Ether ETF (ETHQ.U) AUM': 'https://api.glassnode.com/v1/metrics/institutions/3iq_ethq_aum_sum',
                     '3iQ CoinShares Ether ETF (ETHQ.U) Market Price': 'https://api.glassnode.com/v1/metrics/institutions/3iq_ethq_market_price_usd'},
    'Lightning': {
        'Lightning Network Channel Size (Mean)': 'https://api.glassnode.com/v1/metrics/lightning/channel_size_mean',
        'Lightning Network Channel Size (Median)': 'https://api.glassnode.com/v1/metrics/lightning/channel_size_median',
        'Lightning Network Capacity': 'https://api.glassnode.com/v1/metrics/lightning/network_capacity_sum',
        'Lightning Network Number of Channels': 'https://api.glassnode.com/v1/metrics/lightning/channels_count',
        'Lightning Network Number of Nodes': 'https://api.glassnode.com/v1/metrics/lightning/nodes_count'},
    'Protocols': {'Uniswap Transactions': 'https://api.glassnode.com/v1/metrics/protocols/uniswap_transaction_count',
                  'Uniswap Liquidity': 'https://api.glassnode.com/v1/metrics/protocols/uniswap_liquidity_latest',
                  'Uniswap Volume': 'https://api.glassnode.com/v1/metrics/protocols/uniswap_volume_sum'},
    'Blockchain': {'UTXOs (Total)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_count',
                   'UTXOs Created': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_created_count',
                   'UTXOs Spent': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_spent_count',
                   'UTXO Value Created (Total)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_created_value_sum',
                   'UTXO Value Spent (Total)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_spent_value_sum',
                   'UTXO Value Created (Mean)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_created_value_mean',
                   'UTXO Value Spent (Mean)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_spent_value_mean',
                   'UTXO Value Created (Median)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_created_value_median',
                   'UTXO Value Spent (Median)': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_spent_value_median',
                   'UTXOs in Profit': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_profit_count',
                   'UTXOs in Loss': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_loss_count',
                   'Percent UTXOs in Profit': 'https://api.glassnode.com/v1/metrics/blockchain/utxo_profit_relative',
                   'Block Height': 'https://api.glassnode.com/v1/metrics/blockchain/block_height',
                   'Blocks Mined': 'https://api.glassnode.com/v1/metrics/blockchain/block_count',
                   'Block Interval (Mean)': 'https://api.glassnode.com/v1/metrics/blockchain/block_interval_mean',
                   'Block Interval (Median)': 'https://api.glassnode.com/v1/metrics/blockchain/block_interval_median',
                   'Block Size (Mean)': 'https://api.glassnode.com/v1/metrics/blockchain/block_size_mean',
                   'Block Size (Total)': 'https://api.glassnode.com/v1/metrics/blockchain/block_size_sum'}
}

# 获取所有指标名称及对应的http
all_http = {}
for i, val in enumerate(list(api_http.values())):
    all_http.update(val)


def get_asset_list():
    """
    获取所有支持的资产信息

    :return:
        [
          {
            "symbol": "ETH",
            "name": "Ethereum",
            "isERC20": false,
            "exchanges": ["aggregated","bibox","bigone","binance","bitfinex","bithumb","bittrex","cobinhood","coinex",
                          "gate.io","gemini","hitbtc","huobi","kraken","kucoin","okex","poloniex","zb.com"]
          },
          {
            "symbol": "BTC",
            "name": "Bitcoin"
            "isERC20": false,
            "exchanges": [ ...]
          }
        ]


    """
    http_link = 'https://api.glassnode.com/v1/metrics/assets'

    # make API request
    parameters = {'api_key': API_KEY}

    res = requests.get(http_link, params=parameters)

    # convert to pandas dataframe
    df = pd.read_json(res.text, convert_dates=['t'])

    return df


def get_metrics_list(test_times=1):
    """
    获取所有指标信息

    :return:
        [
            {
                "path": "/v1/metrics/addresses/count",
                "assets": [{"symbol": "MKR", "name": "Maker", "isERC20": true, "isStablecoin": false, "exchanges": ["aggregated", "bibox", "bitfinex", "bittrex"]},
                           {"symbol": "BTC","name": "Bitcoin","isERC20": false,"isStablecoin": false,"exchanges": ["aggregated","binance",]}],
                "currencies": ["NATIVE"],
                "resolutions": ["1h","24h"],
                "formats": ["JSON","CSV"],
            }
        ]

    """
    http_link = 'https://api.glassnode.com/v2/metrics/endpoints'

    # make API request
    parameters = {'api_key': API_KEY}

    ii = 1
    while ii <= test_times:  # 最多重连test_times次
        res = requests.get(http_link, params=parameters)
        if res.status_code == 200:
            break  # 链接成功，不需继续尝试链接
        else:
            ii += 1

    if res.status_code == 500:
        raise RuntimeError(f'已经重连了{test_times}次，还是无法成功链接，请检查网络链接或账户权限')

    # convert to pandas dataframe
    df = pd.read_json(res.text, convert_dates=['t'])

    return df


def get_all_metrics_https():
    # 获取所有指标名称以及对应的http
    all_http = {}
    metric_info = get_metrics_list()
    for metric in metric_info['path']:
        metric_name = metric.split('/')[-1]
        if (metric_name == 'price_usd_close') or (metric_name == 'price_usd_ohlc'):
            continue
        else:
            metric_http = f'https://api.glassnode.com{metric}'
            all_http[metric_name] = metric_http

    return all_http


@deco_retry(retry=5, retry_sleep=5)
def get_prices(ohlc=True, asset='BTC', start_date=None, end_date=None, interval='24h'):
    """
    获取数字货币资产价格序列

    :param bool ohlc: 获取开高低收价格，还是只获取收盘价。默认为True
    :param str asset: 资产类别，默认为'BTC'
    :param str start_date: 数据开始时间， 默认为None, 即从数据最早时间开始获取； 数据格式为'2021-09-22'
    :param str end_date: 数据结束时间，默认为None, 即获取截止最新数据； 数据格式为'2021-09-22'
    :param str interval: 数据频率: 10m, 1h, 24h, 1w, 1month
    :param int test_times: 尝试重连次数， 默认为5次

    :return:
    """

    if ohlc:
        http_link = f'https://api.glassnode.com/v1/metrics/market/price_usd_ohlc'
    else:
        http_link = f'https://api.glassnode.com/v1/metrics/market/price_usd_close'

    print(f'开始获取资产{asset}价格数据')

    # make API request
    parameters = {'a': asset, 'api_key': API_KEY}

    if start_date is not None:
        start_date = date_shifter(start_date, step='days', how_many=1)  # 因为api
        # 日期格式转换
        start_date = str_to_timestamp(start_date, tz_str='+0000')
        parameters.update({'s': start_date})
    if end_date is not None:
        end_date = date_shifter(end_date, step='days', how_many=2)
        # 日期格式转换
        end_date = str_to_timestamp(end_date, tz_str='+0000')
        parameters.update({'u': end_date})
    if interval is not None:
        parameters.update({'i': interval})

    res = requests.get(http_link, params=parameters)
    if res.status_code == 500:
        raise RuntimeError(f'已经重连了5次，还是无法成功链接，请检查网络链接或账户权限')
    if 'unsupported asset' in res.text:
        raise ValueError(f'不支持资产{asset}，请检查名字是否有误')

    # convert to pandas dataframe
    df = pd.read_json(res.text, convert_dates=['t'])
    df.rename(columns={'t': 'end_date'}, inplace=True)

    if ohlc:
        for row_index, row in enumerate(df['o']):
            df.loc[row_index, 'open'] = row['o']
            df.loc[row_index, 'high'] = row['h']
            df.loc[row_index, 'low'] = row['l']
            df.loc[row_index, 'close'] = row['c']
        df.drop(columns=['o'], inplace=True)  # 删除无用列
    else:
        df.rename(columns={'v': 'close'}, inplace=True)

    df.set_index('end_date', inplace=True)
    if interval in ['24h', '1w', '1month']:
        df.index = df.index.strftime("%Y-%m-%d")
    else:
        df.index = df.index.strftime("%Y-%m-%d %H:%M:%S")
    print(f'资产{asset}价格数据获取成功')
    return df


def get_ret(asset='BTC', start_date=None, end_date=None, interval='24h', log_ret=False):
    """
    获取数字货币收益率序列

    :param str or list asset: 数字货币代码，支持单个（str）、多个（list）， 默认为'BTC'
    :param str start_date: 数据开始时间， 默认为None, 即从数据最早时间开始获取； 数据格式为'2021-09-22'
    :param str end_date: 数据结束时间，默认为None, 即获取截止最新数据； 数据格式为'2021-09-22'
    :param str interval: 数据频率: 10m, 1h, 24h, 1w, 1month
    :param bool log_ret: whether to compute using log returns, defaults to False

    :return:
                +-----------+------------+----------------+
                |           |     BTC     |       ETH     |
                +-----------+------------+----------------+
                | 2020-11-30 |    0.01    |     0.0022    |
                | 2020-11-30 |    0.05    |    -0.0812    |
                | 2020-11-30 |    0.02    |     0.0611    |
                +-----------+------------+----------------+

    """

    print(f'开始获取资产{asset}收益率数据')

    if isinstance(asset, str):
        asset = [asset]

    start_date = date_shifter(start_date, step='days', how_many=-1)  # 收益率计算需要用多一天数据

    ret_list = []
    for crypto_code in asset:
        prices_df = get_prices(ohlc=False, asset=crypto_code, start_date=start_date, end_date=end_date, interval=interval)
        if prices_df.shape[0] <= 1:
            LOG.error("输入的价格序列不足两行，无法转换成收益率序列，请重新输入")
            return

        result = prices_df.ffill().bfill().pct_change()
        result = result.iloc[1:]  # 第一期收益为Nan, drop掉
        result.columns = [crypto_code]

        if log_ret:
            result = result + 1
            result = np.log(result)

        ret_list.append(result)

    ret_df = pd.concat(ret_list, axis=1)

    print(f'资产{asset}收益率数据获取成功')
    return ret_df


def get_indicators(indic_code=None, indic_name=None, group='indicators', version='v1', asset='BTC',
                   start_date=None, end_date=None, interval='24h', test_times=5, **kwargs):
    """


    :param str indic_code: 指标编码， 编码是指api链接后英文编码，
                                     例如 https://api.glassnode.com/v1/metrics/indicators/sopr_adjusted，
                                     指标编码为 sopr_adjusted, 指标名称为 asopr;
                                     indic_code 和 indic_name只需输入其中一个就行
    :param str indic_name: 指标名称，上述例子中对应的指标名称为 asopr; indic_code 和 indic_name只需输入其中一个就行
    :param str group: 如果输入的是indic_code, 则需要输入指标对应的组别
    :param str version: 如果输入的是indic_code, 则需要输入api的版本， 默认为v1
    :param str asset: 资产类别，默认为'BTC'
    :param str start_date: 数据开始时间， 默认为None, 即从数据最早时间开始获取； 数据格式为'2021-09-22'
    :param str end_date: 数据结束时间，默认为None, 即获取截止最新数据； 数据格式为'2021-09-22'
    :param str interval: 数据频率: 10m, 1h, 24h, 1w, 1month
    :param int test_times: 尝试重连次数， 默认为5次
    :param kwargs: 关键字参数
        str currency: NATIVE, USD
        str miner： miner name， (see /v1/metrics/transactions/transfers_volume_to_miners_sum/miners for a full list)
        str exchange: exchange name (see endpoints for a full list)

    :return:
    """

    if indic_code is None:
        http_link = all_http[indic_name]
    else:
        http_link = f'https://api.glassnode.com/{version}/metrics/{group}/{indic_code}'
        indic_name = list(all_http.keys())[list(all_http.values()).index(http_link)]

    print(f'开始获取指标{indic_name}数据')

    # make API request
    parameters = {'a': asset, 'api_key': API_KEY}

    currency = kwargs.pop('currency', None)
    miner = kwargs.pop('miner', None)
    exchange = kwargs.pop('exchange', None)

    if start_date is not None:
        start_date = date_shifter(start_date, step='days', how_many=1)
        # 日期格式转换
        start_date = str_to_timestamp(start_date)
        parameters.update({'s': start_date})
    if end_date is not None:
        end_date = date_shifter(end_date, step='days', how_many=1)
        # 日期格式转换
        end_date = str_to_timestamp(end_date)
        parameters.update({'u': end_date})
    if interval is not None:
        parameters.update({'i': interval})
    if currency is not None:
        parameters.update({'c': currency})
    if miner is not None:
        parameters.update({'miner': miner})
    if exchange is not None:
        parameters.update({'e': exchange})

    ii = 1
    while ii <= test_times:  # 最多重连test_times次
        e = False
        try:
            res = requests.get(http_link, params=parameters)
            if res.status_code == 200:
                break  # 链接成功，不需继续尝试链接
            elif res.status_code == 400:
                print(f'指标{indic_name}数据获取失败，{res.status_code}; {res.text}')
                return None
            else:
                print(f'指标{indic_name}数据获取失败，{res.status_code}, {res.text}')
                time.sleep(10)  # 等待10秒，重新尝试连接
                ii += 1
        except Exception as e:
            print(f'指标{indic_name}数据获取异常， {str(e)}')
            time.sleep(10)  # 等待10秒，重新尝试连接
            ii += 1

    if e:
        raise RuntimeError(f'已经重连了{test_times}次, 指标{indic_name}数据获取还是异常， {str(e)}')
    if res.status_code != 200:  # 重连test_times，依旧出现出400外的错误
        raise RuntimeError(f'已经重连了{test_times}次，还是无法成功链接，请检查网络链接或账户权限')
    if res.text == '[]':
        print(f'指标{indic_name}数据获取为空')
        return None

    # convert to pandas dataframe
    try:
        df = pd.read_json(res.text, convert_dates=['t'])
    except ValueError as err:  # 直接转换成DataFrame时，有时候会报Value too big的错
        data = json.loads(res.text, )
        columns = list(set(data[0].keys()))
        df = pd.DataFrame.from_records(data, columns=columns)
        df['t'] = df['t'].apply(timestamp_to_datetime)
    except Exception:  # 其他未知错误
        print(f'指标{indic_name}数据获取正常，但转换成Dataframe时失败')
        return None

    df.rename(columns={'t': 'end_date'}, inplace=True)
    df.set_index('end_date', inplace=True)
    df.index = df.index.strftime("%Y-%m-%d")
    if len(df.columns) == 1:
        df.columns = [f'{indic_name}']
        if isinstance(df.iloc[0, 0], dict):  # 元素的类型是dict
            df = pd.DataFrame([i[0] for i in df.values], index=df.index)
    else:
        print(f'指标{indic_name}数据为多列，无法对指标列重命名')

    print(f'指标{indic_name}数据获取成功')

    return df


if __name__ == '__main__':
    aa = get_metrics_list()
    # get_asset_list()
    # get_indicators()
    # get_prices(ohlc=False, asset='BTC', start_date='2015-01-01', end_date='2021-10-11', interval='24h')
    # get_ret(asset='BTC', start_date='2015-01-01', end_date='2021-10-11', log_ret=True)
    # get_ret(asset=['BTC', 'ETH'], start_date='2015-01-01', end_date='2021-10-12', log_ret=True)
    # get_indicators(indic_code='sopr', asset='BTC', start_date='2021-09-01', end_date='2021-09-25')
    # indic_name = 'Supply of Top 1% Addresses'
    indic_name = 'Herfindahl Index'
    aa = get_indicators(indic_name=indic_name, asset='BTC', start_date='2015-01-01', end_date='2021-09-25')
